#include "BufManager.h"

namespace android::wmark
{
    BufManager::BufManager()
    {
        mWmarkDev = WmarkDev::getInstance();
        mIonDev = new IonDev();

        minitDmaFlag = false;
        initDmaBuf(DMA_BUF_COUNT, DMA_BUF_W, DMA_BUF_H, DMA_BUF_CH);
        initWmarkBuf(WMARK_BUF_COUNT, WMARK_BUF_W, WMARK_BUF_H, WMARK_BUF_CH);

        mWmarkDev->registerCtlMsgCallback(this);
        mWmarkDev->start();
    }

    BufManager::~BufManager()
    {
        if (mIonDev)
        {
            delete mIonDev;
            mIonDev = NULL;
        }

        deleteDmaInfo();
    }

    int BufManager::initDmaBuf(int num, int w, int h, int ch)
    {
        int ret;
        unsigned long bufLen = w * h * ch;

        mutex.lock();

        if (minitDmaFlag)
        {
            ret = 0;
            goto free_lock;
        }

        if (num > BUF_FD_MAX)
        {
            ALOGE("%s %d num=%d > %d", __func__, __LINE__, num, BUF_FD_MAX);
            ret = -1;
            goto free_lock;
        }

        ret = allocDmaInfo(num);
        if (-1 == ret)
        {
            ALOGE("%s %d : fail", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }

        if (mIonDev)
        {
            for (size_t i = 0; i < mDmaBufArrayLen; i++)
            {
                ret = mIonDev->createBuf(mDmaBufArray[i], bufLen);
                if (-1 == ret)
                {
                    ret = -1;
                    goto free_lock;
                }
            }
        }
        else
        {
            ALOGE("%s %d : fail", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }

        if (mWmarkDev)
        {
            int *fds = (int *)malloc(mDmaBufArrayLen * sizeof(int));
            for (size_t i = 0; i < mDmaBufArrayLen; i++)
            {
                fds[i] = mDmaBufArray[i].buffd;
            }

            mWmarkDev->initBufsNum(mDmaBufArrayLen, bufLen, fds);
            mWmarkDev->notifyStateChange(S_M_INIT_OK_EX);
            free(fds);
        }
        else
        {
            ALOGE("%s %d : fail", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }

        ret = 0;
        minitDmaFlag = true;
        ALOGD("%s %d: minitDmaFlag=%s", __func__, __LINE__, minitDmaFlag ? "true" : "false");

    free_lock:
        mutex.unlock();
        return ret;
    }

    int BufManager::allocDmaInfo(int num)
    {
        if (num > BUF_FD_MAX)
        {
            ALOGE("%s %d num=%d > %d", __func__, __LINE__, num, BUF_FD_MAX);
            return -1;
        }

        if (mDmaBufArray)
        {
            ALOGE("%s %d : error: mDmaBufArray!=NULL\n", __func__, __LINE__);
            return 0;
        }

        mDmaBufArrayLen = num;
        mDmaBufArray = (struct ion_buffer_info *)malloc(mDmaBufArrayLen * sizeof(struct ion_buffer_info));
        if (!mDmaBufArray)
        {
            ALOGE("mDmaBufArray == NULL fail \n");
            return -1;
        }

        return 0;
    }

    int BufManager::deleteDmaInfo()
    {
        mutex.lock();
        if (mDmaBufArray)
        {
            free(mDmaBufArray);
            mDmaBufArray = NULL;
        }
        mutex.unlock();
        return 0;
    }

    int BufManager::initWmarkBuf(int num, int w, int h, int ch)
    {
        if (!mWmarkDev)
        {
            ALOGE("%s %d : error", __func__, __LINE__);
            return -1;
        }
        return mWmarkDev->initWmarkBuf(num, w, h, ch);
    }

    int BufManager::sendNotify(uint8_t *srcBuf, uint64_t srcBufLen, wmark_buf_t &_info)
    {
        int ret = -1;
        int dmaBufIndex = -1;
        struct ion_buffer_info *dmaBufInfo;

        mutex.lock();

        if (!srcBuf || !minitDmaFlag || !mWmarkDev || !mDmaBufArray)
        {
            ALOGE("%s %d : arg error", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }

        dmaBufIndex = mWmarkDev->getFreeDmaBufIndex();
        if (dmaBufIndex < 0 || dmaBufIndex >= mDmaBufArrayLen)
        {
            ALOGE("%s %d : getFreeDmaBufIndex fail", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }

        dmaBufInfo = &mDmaBufArray[dmaBufIndex];
        if (srcBufLen > dmaBufInfo->buflen || !dmaBufInfo->buffer)
        {
            ALOGE("%s %d : error", __func__, __LINE__);
            ret = -1;
            goto free_lock;
        }
        memset(dmaBufInfo->buffer, 0, srcBufLen);
        memcpy(dmaBufInfo->buffer, srcBuf, srcBufLen);
        _info.index = dmaBufIndex;
        // checkData(dmaBufInfo->buffer, srcBufLen);
        ALOGD("set use index=%d", _info.index);

        mWmarkDev->setUseDmaBufIndex(_info);

        ret = 0;

    free_lock:
        mutex.unlock();

        return ret;
    }

    void BufManager::checkData(uint8_t *buf, uint64_t len)
    {
        int i;
        unsigned char *ptr = (unsigned char *)buf;
        int cout = 0;

        if (!ptr)
        {
            fprintf(stderr, "<%s>: Invalid buffer...\n", __func__);
            return;
        }

        printf("Read buffer content:\n");
        for (i = 0; i < len; i++)
        {
            if (ptr[i] != 0)
            {
                cout++;
            }
        }

        ALOGD("%s %d !=0 cout=%d\n", __func__, __LINE__, cout);
    }

    int BufManager::uninitDmaBuf()
    {
        int ret = -1;

        mutex.lock();

        if (mIonDev)
        {
            for (size_t i = 0; i < mDmaBufArrayLen; i++)
            {
                mIonDev->ionCloseBufferFd(&mDmaBufArray[i]);
            }
        }

        ret = 0;
        minitDmaFlag = false;
        ALOGD("%s %d: minitDmaFlag=%s", __func__, __LINE__, minitDmaFlag ? "true" : "false");

        mutex.unlock();

        return ret;
    }

    void BufManager::onResult(control_msg_t &info)
    {
        switch (info.state)
        {
        case S_M_OPEN_IM:
            ALOGD("%s %d : S_M_OPEN_IM\n", __func__, __LINE__);
            break;
        case S_M_INIT_OK_IM:
            ALOGD("%s %d : S_M_INIT_OK_IM\n", __func__, __LINE__);
            break;
        case S_M_INIT_ERROR_IM:
            ALOGD("%s %d : S_M_INIT_ERROR_IM\n", __func__, __LINE__);
            break;
        case S_M_CLOSE_IM:
            ALOGD("%s %d : S_M_CLOSE_IM\n", __func__, __LINE__);
            uninitDmaBuf();
            initDmaBuf(DMA_BUF_COUNT, DMA_BUF_W, DMA_BUF_H, DMA_BUF_CH);
            break;

        default:
            ALOGE("%s %d : state fail\n", __func__, __LINE__);
            break;
        }
        return;
    }
}
